#include "stm32f4xx.h"
#include <board.h>
#include <rtthread.h>

#include "stm32f4_discovery.h"
#include "usbh_core.h"
#include "usbh_msc_usr.h"
#include "usbh_msc_core.h"
#include <rtdevice.h>
#include "key.h"
#include "mp3.h"
#include "stm32f4_discovery_audio_codec.h"
#include "stm32f4_discovery_lis302dl.h"
#include "usbh_core.h"
#include "usbh_msc_usr.h"
#include "usbh_msc_core.h"

#ifdef RT_USING_DFS
/* dfs init */
#include <dfs_init.h>
/* dfs filesystem:ELM filesystem init */
#include <dfs_elm.h>
/* dfs Filesystem APIs */
#include <dfs_fs.h>
#include <dfs_posix.h>
#endif

#include "file_scan.h"
#include "play_bg.h"

extern __IO uint8_t  LED_Toggle;

rt_mailbox_t my_mb;

/**
* @brief  configure the mems accelometer
* @param  None
* @retval None
*/
static void Mems_Config(void)
{ 
	uint8_t ctrl = 0;

	LIS302DL_InitTypeDef  LIS302DL_InitStruct;
	LIS302DL_InterruptConfigTypeDef LIS302DL_InterruptStruct;  

	/* Set configuration of LIS302DL*/
	LIS302DL_InitStruct.Power_Mode = LIS302DL_LOWPOWERMODE_ACTIVE;
	LIS302DL_InitStruct.Output_DataRate = LIS302DL_DATARATE_100;
	LIS302DL_InitStruct.Axes_Enable = LIS302DL_X_ENABLE | LIS302DL_Y_ENABLE | LIS302DL_Z_ENABLE;
	LIS302DL_InitStruct.Full_Scale = LIS302DL_FULLSCALE_2_3;
	LIS302DL_InitStruct.Self_Test = LIS302DL_SELFTEST_NORMAL;
	LIS302DL_Init(&LIS302DL_InitStruct);

	/* Set configuration of Internal High Pass Filter of LIS302DL*/
	LIS302DL_InterruptStruct.Latch_Request = LIS302DL_INTERRUPTREQUEST_LATCHED;
	LIS302DL_InterruptStruct.SingleClick_Axes = LIS302DL_CLICKINTERRUPT_Z_ENABLE;
	LIS302DL_InterruptStruct.DoubleClick_Axes = LIS302DL_DOUBLECLICKINTERRUPT_Z_ENABLE;
	LIS302DL_InterruptConfig(&LIS302DL_InterruptStruct);

	/* Configure Interrupt control register: enable Click interrupt on INT1 and
	 INT2 on Z axis high event */
	ctrl = 0x3F;
	LIS302DL_Write(&ctrl, LIS302DL_CTRL_REG3_ADDR, 1);

	/* Enable Interrupt generation on click on Z axis */
	ctrl = 0x50;
	LIS302DL_Write(&ctrl, LIS302DL_CLICK_CFG_REG_ADDR, 1);

	/* Configure Click Threshold on X/Y axis (10 x 0.5g) */
	ctrl = 0xAA;
	LIS302DL_Write(&ctrl, LIS302DL_CLICK_THSY_X_REG_ADDR, 1);

	/* Configure Click Threshold on Z axis (10 x 0.5g) */
	ctrl = 0x0A;
	LIS302DL_Write(&ctrl, LIS302DL_CLICK_THSZ_REG_ADDR, 1);

	/* Enable interrupt on Y axis high event */
	ctrl = 0x4C;
	LIS302DL_Write(&ctrl, LIS302DL_FF_WU_CFG1_REG_ADDR, 1);

	/* Configure Time Limit */
	ctrl = 0x03;
	LIS302DL_Write(&ctrl, LIS302DL_CLICK_TIMELIMIT_REG_ADDR, 1);

	/* Configure Latency */
	ctrl = 0x7F;
	LIS302DL_Write(&ctrl, LIS302DL_CLICK_LATENCY_REG_ADDR, 1);

	/* Configure Click Window */
	ctrl = 0x7F;
	LIS302DL_Write(&ctrl, LIS302DL_CLICK_WINDOW_REG_ADDR, 1);
    
}

/**
  * @brief  Configures EXTI Line0 (connected to PA0 pin) in interrupt mode
  * @param  None
  * @retval None
  */
static void EXTILine_Config(void)
{
	GPIO_InitTypeDef   GPIO_InitStructure;
	NVIC_InitTypeDef   NVIC_InitStructure;
	EXTI_InitTypeDef   EXTI_InitStructure;
	/* Enable GPIOA clock */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	/* Enable SYSCFG clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	/* Configure PE0 and PE1 pins as input floating */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
	GPIO_Init(GPIOE, &GPIO_InitStructure);

	/* Connect EXTI Line to PE1 pins */
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource1);

	/* Configure EXTI Line1 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line1;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);

	/* Enable and set EXTI Line0 Interrupt to the lowest priority */
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

void player_dec_bg_tid_exit(void)
{
	rt_mb_send(my_mb,MB_PLAYER_STOP);
	rt_thread_delay(80);
}

rt_err_t player_dec_bg_tid_resume(void)
{
	rt_thread_t tid;
	
	tid = rt_thread_find("ply_bg");
	if(tid!=RT_NULL)
	{
		return (rt_thread_resume(tid));
	}
	
	return RT_EOK;
}

rt_err_t player_dec_bg_tid_suspend(void)
{
	rt_thread_t tid;
	
	tid = rt_thread_find("ply_bg");
	if(tid!=RT_NULL)
	{
		return(rt_thread_suspend(tid));
	}
	return RT_EOK;
}

static void playerbg_entry(void *parameter)
{
	/* LED Blue Start toggling */
	LED_Toggle = 6;		
	
	mp3(play_list_get_current_fn());
	EVAL_AUDIO_Stop(CODEC_PDWN_SW);
	if(!HCD_IsDeviceConnected(&USB_OTG_Core))
	{
		/* Green LED toggling */
		LED_Toggle = 4;
	}
	else
	{
		rt_uint16_t iMsg;
		iMsg = MSG_FILE_AUTO_END;
		rt_mq_send(msg_q,&iMsg,sizeof(iMsg));		
	}
}

void player_bg_init(void)
{
	rt_thread_t init_tid;

    init_tid = rt_thread_create("ply_bg", playerbg_entry, RT_NULL,
                                     3*1024, 4, 20);
    if (init_tid != RT_NULL)
        rt_thread_startup(init_tid);
}

static void playersvr_entry(void *parameter)
{
	rt_uint16_t iMsg;
	rt_device_t dev=RT_NULL;
	
	my_mb = rt_mb_create("my_mb",1,RT_IPC_FLAG_FIFO);
	
	/* MEMS Accelerometre configure to manage PAUSE, RESUME and Controle Volume operation */
	Mems_Config();

	/* EXTI configue to detect interrupts on Z axis click and on Y axis high event */
	EXTILine_Config();
	
	while(1)
	{
		rt_mq_recv(msg_q,&iMsg,sizeof(iMsg),RT_WAITING_FOREVER);
		
		switch(iMsg)
		{
			case MSG_FS_INIT_UDISK:
				dev = rt_device_find("udisk0");
				if(dev==RT_NULL)
				{
					rt_hw_udisk_init();
					/* mount sd card fat partition 1 as root directory */
					if (dfs_mount("udisk0", "/", "elm", 0, 0) == 0)
					{
						printf("Udisk File System initialzation OK!\n");
						play_list_disk_scan(DISK_SCAN_ALL);
						if(play_list_total_items())
						{
							play_list_set_current_item(1);
						}
						else
						{
							play_list_set_current_item(1);
						}
						iMsg = START_PLAY;
						rt_mq_urgent(msg_q,&iMsg,sizeof(iMsg));
					}
					else
					{
						printf("Udisk File System initialzation false!\n");
					}
				}
				break;
				
			case MSG_FS_INIT_SD:
				dev = rt_device_find("sd0");
				if(dev==RT_NULL)
				{
					rt_hw_udisk_init();
					/* mount sd card fat partition 1 as root directory */
					if (dfs_mount("sd0", "/", "elm", 0, 0) == 0)
					{
						printf("SD File System initialzation OK!\n");
						play_list_disk_scan(DISK_SCAN_ALL);
						if(play_list_total_items())
						{
							play_list_set_current_item(1);
						}
						else
						{
							play_list_set_current_item(1);
						}
						iMsg = START_PLAY;
						rt_mq_urgent(msg_q,&iMsg,sizeof(iMsg));
					}
					else
					{
						printf("SD File System initialzation false!\n");
					}
				}
				break;
			
			case PS_ENTER:
				if(player_dec_bg_tid_suspend()==RT_EOK)
				{
					EVAL_AUDIO_PauseResume(AUDIO_PAUSE);
					/* Pause Playing wave */
					LED_Toggle = 0;					
					break;
				}
				if(player_dec_bg_tid_resume()==RT_EOK)
				{
					EVAL_AUDIO_PauseResume(AUDIO_RESUME);
					LED_Toggle = 6;
					break;
				}
				break;

			case PH_UP:
				rt_mb_send(my_mb,MB_PLAYER_FR);
				rt_thread_delay(10);
				break;

			case PH_DOWN:
				rt_mb_send(my_mb,MB_PLAYER_FF);
				rt_thread_delay(10);
				break;
			
			case PU_UP:
			case PU_DOWN:
				break;
			
			case PS_UP:
				player_dec_bg_tid_exit();
				play_list_prev();
				iMsg = START_PLAY;
				rt_mq_urgent(msg_q,&iMsg,sizeof(iMsg));
				break;
			
			case MSG_FILE_AUTO_END:
			case PS_DOWN:
				player_dec_bg_tid_exit();
				play_list_next();
				iMsg = START_PLAY;
				rt_mq_urgent(msg_q,&iMsg,sizeof(iMsg));
				break;

			case START_PLAY:
				rt_mq_control(msg_q,RT_IPC_CMD_RESET,RT_NULL);
				play_list_init_item(play_list_get_current_index());
				player_bg_init();
				break;
		}
	}
}

void player_svr_init(void)
{
	rt_thread_t init_tid;

    init_tid = rt_thread_create("ply_svr", playersvr_entry, RT_NULL,
                                     3*1024, 3, 20);
    if (init_tid != RT_NULL)
        rt_thread_startup(init_tid);
}
